﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.Text;
using Acando.Dynamics.CRM.Silverlight.Library.MetaSdk;
using System.Collections.Generic;

namespace Acando.Dynamics.CRM.Silverlight.Library.Helper
{
    public class MetaDataSerializationHelper
    {
        # region Known Types

        private static List<Type> knownTypes = new List<Type>() {  typeof( AttributeMetadata),
                                                            typeof( LookupAttributeMetadata),
                                                            typeof( PicklistAttributeMetadata),
                                                            typeof( DateTimeAttributeMetadata), 
                                                            typeof( DecimalAttributeMetadata), 
                                                            typeof( MoneyAttributeMetadata), 
                                                            typeof( MemoAttributeMetadata), 
                                                            typeof( IntegerAttributeMetadata), 
                                                            typeof( StatusAttributeMetadata),
                                                            typeof( BooleanAttributeMetadata), 
                                                            typeof( FloatAttributeMetadata), 
                                                            typeof( StateAttributeMetadata), 
                                                            typeof( StringAttributeMetadata), 
                                                            typeof( MetadataItems), 
                                                            typeof( MetaSdk.Key), 
                                                            typeof( MetaSdk.LocLabel), 
                                                            typeof( MetaSdk.OfflineOrigin), 
                                                            typeof( ManyToManyMetadata), 
                                                            typeof( OneToManyMetadata), 
                                                            typeof( DisplayMasks), 
                                                            typeof( MetaSdk.CrmBoolean), 
                                                            typeof( MetaSdk.CrmNumber), 
                                                            typeof( MetaSdk.CrmLabel), 
                                                            typeof( CrmCascadeType), 
                                                            typeof( MetaSdk.CrmDateTime), 
                                                            typeof( CrmDateTimeFormat), 
                                                            typeof( DateTimeFormat), 
                                                            typeof( CrmDouble), 
                                                            typeof( MetaSdk.CrmFloat), 
                                                            typeof( ImeMode), 
                                                            typeof( RelationshipMetadata), 
                                                            typeof( Option), 
                                                            typeof( StateOption), 
                                                            typeof( StatusOption), 
                                                            typeof( StringFormat), 
                                                            typeof( CrmStringFormat), 
                                                            typeof( SecurityPrivilegeMetadata), 
                                                            typeof( OwnershipTypes), 
                                                            typeof( PrivilegeType),     
                                                            typeof( CrmAttributeType), 
                                                            typeof( AttributeType), 
                                                            typeof( CrmAttributeRequiredLevel), 
                                                            typeof( AttributeRequiredLevel), 
                                                            typeof( CrmOwnershipTypes), 
                                                            typeof( CrmNullable) };
        # endregion

        public static String Serialize(EntityMetadata data)
        {
            if (data == null) throw new ArgumentNullException("data");
            DataContractSerializer serializer = new DataContractSerializer(typeof(EntityMetadata), knownTypes);
            MemoryStream memoryStream = new MemoryStream();
            serializer.WriteObject(memoryStream, data);

            String seralObj = Encoding.UTF8.GetString(memoryStream.GetBuffer(), 0, (int)memoryStream.Position);
            memoryStream.Close();

            return seralObj;

        }

        public static String Serialize<T>(T data)
        {
            if (data == null) throw new ArgumentNullException("data");
            DataContractSerializer serializer = new DataContractSerializer(typeof(T), knownTypes);
            MemoryStream memoryStream = new MemoryStream();
            serializer.WriteObject(memoryStream, data);

            String seralObj = Encoding.UTF8.GetString(memoryStream.GetBuffer(), 0, (int)memoryStream.Position);
            memoryStream.Close();

            return seralObj;

        }

        public static T DeserializeXmlTo<T>(string serialized)
        {
            if (String.IsNullOrEmpty(serialized))
                throw new ArgumentNullException("serialized");

            DataContractSerializer serializer = new DataContractSerializer(typeof(T), knownTypes);

            MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(serialized));
            try
            {
                var deserializedObj = (T)serializer.ReadObject(memoryStream);

                if (deserializedObj == null)
                    throw new Exception("Could not deserialize string to EntityMetadata object.");
                else
                {
                    memoryStream.Close();
                    return deserializedObj;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        

        public static EntityMetadata DeserializeXmlToEntityMetadata(byte[] xml)
        {
            using (MemoryStream xmlStream = new MemoryStream(xml))
            {
                DataContractSerializer serializer = new DataContractSerializer(typeof(EntityMetadata), knownTypes);

                try
                {

                    EntityMetadata deserializedObj = serializer.ReadObject(xmlStream) as EntityMetadata;

                    if (deserializedObj == null)
                        throw new Exception("Could not deserialize string to EntityMetadata object.");
                    else
                        return deserializedObj;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        public static EntityMetadata DeserializeToEntityMetadata(String serialized)
        {

            if (String.IsNullOrEmpty(serialized))
                throw new ArgumentNullException("serialized");

            DataContractSerializer serializer = new DataContractSerializer(typeof(EntityMetadata), knownTypes);

            MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(serialized));
            try
            {
                var deserializedObj = (EntityMetadata)serializer.ReadObject(memoryStream);

                if (deserializedObj == null)
                    throw new Exception("Could not deserialize string to EntityMetadata object.");
                else
                {
                    memoryStream.Close();
                    return deserializedObj;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }

    public class SerializationHelper
    {
        private SerializationHelper()
        {
        }

        public static byte[] SerializeToXml<T>(T obj) where T : class
        {
            using (MemoryStream xmlStream = new MemoryStream())
            {
                XmlSerializer serializer = new XmlSerializer(typeof(T));
                serializer.Serialize(xmlStream, obj);

                return xmlStream.ToArray();
            }
        }

        public static T DeserializeXmlTo<T>(byte[] xml) where T : class
        {
            using (MemoryStream xmlStream = new MemoryStream(xml))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(T));
                return serializer.Deserialize(xmlStream) as T;
            }
        }

    }
}
